/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use crate::common::constants::ErrorCode;
use crate::ensure_or_return_val;
use crate::entry::user_auth_entry::{
    handle_rust_command, handle_rust_env_init, handle_rust_env_uninit,
};
use crate::traits::command_manager::{Caller};
use crate::{log_e, CString};
use core::mem;
use core::slice;
use serde::{Deserialize, Serialize};
use serde_big_array::BigArray;

pub const PUBLIC_KEY_LEN_FFI: usize = 32;
pub const CHALLENGE_LEN_FFI: usize = 32;
pub const UDID_LEN_FFI: usize = 64;
pub const MAX_EVENT_NUM_FFI: usize = 20;
pub const ROOT_SECRET_LEN_FFI: usize = 32;
pub const MAX_AUTH_TOKEN_LEN_FFI: usize = 1024;
pub const MAX_CREDENTIAL_NUM_FFI: usize = 40;
pub const MAX_EXECUTOR_NUM_FFI: usize = 32;
pub const MAX_MSG_LEN_FFI: usize = 1024;
pub const MAX_SCHEDULE_NUM_FFI: usize = 2;
pub const MAX_TEMPLATE_ID_NUM_FFI: usize = 32;
pub const MAX_USER_NUM_FFI: usize = 6;
pub const MAX_LONG_C_STRING_LEN_FFI: usize = 200;
pub const MAX_C_STRING_LEN_FFI: usize = 50;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct AuthTokenArrayFfi {
    pub data: [u8; MAX_AUTH_TOKEN_LEN_FFI],
    pub len: u32,
}

impl Default for AuthTokenArrayFfi {
    fn default() -> Self {
        AuthTokenArrayFfi {
            data: [0; MAX_AUTH_TOKEN_LEN_FFI],
            len: 0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct MessageArrayFfi {
    pub data: [u8; MAX_MSG_LEN_FFI],
    pub len: u32,
}

impl Default for MessageArrayFfi {
    fn default() -> Self {
        MessageArrayFfi {
            data: [0; MAX_MSG_LEN_FFI],
            len: 0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct TemplateIdArrayFfi {
    pub data: [u64; MAX_TEMPLATE_ID_NUM_FFI],
    pub len: u32,
}

impl Default for TemplateIdArrayFfi {
    fn default() -> Self {
        TemplateIdArrayFfi {
            data: [0; MAX_TEMPLATE_ID_NUM_FFI],
            len: 0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct ExecutorIndexArrayFfi {
    pub data: [u64; MAX_EXECUTOR_NUM_FFI],
    pub len: u32,
}

impl Default for ExecutorIndexArrayFfi {
    fn default() -> Self {
        ExecutorIndexArrayFfi {
            data: [0; MAX_EXECUTOR_NUM_FFI],
            len: 0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct UserIdArrayFfi {
    pub data: [i32; MAX_USER_NUM_FFI],
    pub len: u32,
}

impl Default for UserIdArrayFfi {
    fn default() -> Self {
        UserIdArrayFfi {
            data: [0; MAX_USER_NUM_FFI],
            len: 0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct Int32ArrayFfi {
    pub data: [i32; MAX_CREDENTIAL_NUM_FFI],
    pub len: u32,
}

impl Default for Int32ArrayFfi {
    fn default() -> Self {
        Int32ArrayFfi {
            data: [0; MAX_CREDENTIAL_NUM_FFI],
            len: 0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct PlaceHolderFfi {
    pub place_holder: u8,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct CStringFfi {
    pub data: [u8; MAX_C_STRING_LEN_FFI],
    pub len: u32,
}

impl Default for CStringFfi {
    fn default() -> Self {
        CStringFfi {
            data: [0; MAX_C_STRING_LEN_FFI],
            len: 0,
        }
    }
}

impl TryFrom<CString> for CStringFfi {
    type Error = ErrorCode;

    fn try_from(value: CString) -> core::result::Result<Self, ErrorCode> {
        let bytes = value.as_bytes();
        let len = bytes.len();
        if len > MAX_C_STRING_LEN_FFI {
            log_e!(
                "String length {} exceeds max length {}",
                len,
                MAX_C_STRING_LEN_FFI
            );
            return Err(ErrorCode::BadParam);
        }
        let mut data = [0; MAX_C_STRING_LEN_FFI];
        data[..len].copy_from_slice(bytes);
        Ok(CStringFfi {
            data,
            len: len as u32,
        })
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct LongCStringFfi {
    pub data: [u8; MAX_LONG_C_STRING_LEN_FFI],
    pub len: u32,
}

impl Default for LongCStringFfi {
    fn default() -> Self {
        LongCStringFfi {
            data: [0; MAX_LONG_C_STRING_LEN_FFI],
            len: 0,
        }
    }
}

impl TryFrom<CString> for LongCStringFfi {
    type Error = ErrorCode;

    fn try_from(value: CString) -> core::result::Result<Self, ErrorCode> {
        let bytes = value.as_bytes();
        let len = bytes.len();
        if len > MAX_LONG_C_STRING_LEN_FFI {
            log_e!(
                "String length {} exceeds max length {}",
                len,
                MAX_LONG_C_STRING_LEN_FFI
            );
            return Err(ErrorCode::BadParam);
        }
        let mut data = [0; MAX_LONG_C_STRING_LEN_FFI];
        data[..len].copy_from_slice(bytes);
        Ok(LongCStringFfi {
            data,
            len: len as u32,
        })
    }
}

#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct EventFfi {
    pub time: u64,
    pub file_name: CStringFfi,
    pub line_number: u32,
    pub event_type: i32,
    pub event_info: LongCStringFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct EventArrayFfi {
    pub data: [EventFfi; MAX_EVENT_NUM_FFI],
    pub len: u32,
}

impl Default for EventArrayFfi {
    fn default() -> Self {
        EventArrayFfi {
            data: [EventFfi::default(); MAX_EVENT_NUM_FFI],
            len: 0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct CommonOutputFfi {
    pub result: i32,
    pub has_fatal_error: bool,
    pub events: EventArrayFfi,
}

impl Default for CommonOutputFfi {
    fn default() -> Self {
        CommonOutputFfi {
            result: 0,
            has_fatal_error: false,
            events: EventArrayFfi::default(),
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct EnrolledInfoFfi {
    pub enrolled_id: u64,
    pub auth_type: i32,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct EnrolledInfoArrayFfi {
    pub data: [EnrolledInfoFfi; MAX_CREDENTIAL_NUM_FFI],
    pub len: u32,
}

impl Default for EnrolledInfoArrayFfi {
    fn default() -> Self {
        EnrolledInfoArrayFfi {
            data: [EnrolledInfoFfi::default(); MAX_CREDENTIAL_NUM_FFI],
            len: 0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct UserInfoFfi {
    pub secure_uid: u64,
    pub pin_sub_type: i32,
    pub enrolled_infos: EnrolledInfoArrayFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct UserInfoArrayFfi {
    pub data: [UserInfoFfi; MAX_USER_NUM_FFI],
    pub len: u32,
}

impl Default for UserInfoArrayFfi {
    fn default() -> Self {
        UserInfoArrayFfi {
            data: [UserInfoFfi::default(); MAX_USER_NUM_FFI],
            len: 0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct ExtUserInfoFfi {
    pub user_id: i32,
    pub user_info: UserInfoFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct ExtUserInfoArrayFfi {
    pub data: [ExtUserInfoFfi; MAX_USER_NUM_FFI],
    pub len: u32,
}

impl Default for ExtUserInfoArrayFfi {
    fn default() -> Self {
        ExtUserInfoArrayFfi {
            data: [ExtUserInfoFfi::default(); MAX_USER_NUM_FFI],
            len: 0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct CredentialInfoFfi {
    pub credential_id: u64,
    pub executor_index: u64,
    pub template_id: u64,
    pub auth_type: i32,
    pub executor_matcher: u32,
    pub executor_sensor_hint: u32,
    pub auth_sub_type: i32,
    pub is_abandoned: u8,
    pub validity_period: i64,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct CredentialArrayFfi {
    pub data: [CredentialInfoFfi; MAX_CREDENTIAL_NUM_FFI],
    pub len: u32,
}

impl Default for CredentialArrayFfi {
    fn default() -> Self {
        CredentialArrayFfi {
            data: [CredentialInfoFfi::default(); MAX_CREDENTIAL_NUM_FFI],
            len: 0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct ExecutorSendMsgFfi {
    pub executor_index: u64,
    pub command_id: i32,
    pub msg: MessageArrayFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct ExecutorSendMsgArrayFfi {
    pub data: [ExecutorSendMsgFfi; MAX_EXECUTOR_NUM_FFI],
    pub len: u32,
}

impl Default for ExecutorSendMsgArrayFfi {
    fn default() -> Self {
        ExecutorSendMsgArrayFfi {
            data: [ExecutorSendMsgFfi::default(); MAX_EXECUTOR_NUM_FFI],
            len: 0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct AuthResultInfoFfi {
    pub result: i32,
    pub lockout_duration: i32,
    pub remain_attempts: i32,
    pub msgs: ExecutorSendMsgArrayFfi,
    pub token: AuthTokenArrayFfi,
    pub root_secret: MessageArrayFfi,
    pub user_id: i32,
    pub credential_id: u64,
    pub pin_expired_info: i64,
    pub remote_auth_result_msg: MessageArrayFfi,
    pub re_enroll_flag: bool,
}

#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct EnrolledStateFfi {
    pub credential_digest: u64,
    pub credential_count: u16,
}

#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct ScheduleInfoFfi {
    pub schedule_id: u64,
    pub template_ids: TemplateIdArrayFfi,
    pub auth_type: i32,
    pub executor_matcher: u32,
    pub schedule_mode: i32,
    pub executor_indexes: ExecutorIndexArrayFfi,
    pub executor_messages: [MessageArrayFfi; MAX_EXECUTOR_NUM_FFI],
    pub executor_message_count: u32,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct ScheduleInfoArrayFfi {
    pub data: [ScheduleInfoFfi; MAX_SCHEDULE_NUM_FFI],
    pub len: u32,
}

impl Default for ScheduleInfoArrayFfi {
    fn default() -> Self {
        ScheduleInfoArrayFfi {
            data: [ScheduleInfoFfi::default(); MAX_SCHEDULE_NUM_FFI],
            len: 0,
        }
    }
}

// Init
#[repr(C)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct InitInputFfi {
    #[serde(with = "BigArray")]
    pub device_udid: [u8; UDID_LEN_FFI],
}

impl Default for InitInputFfi {
    fn default() -> Self {
        InitInputFfi {
            device_udid: [0; UDID_LEN_FFI],
        }
    }
}

pub type InitOutputFfi = PlaceHolderFfi;

// AddExecutor
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ExecutorRegisterInfoFfi {
    pub auth_type: i32,
    pub executor_role: i32,
    pub executor_sensor_hint: u32,
    pub executor_matcher: u32,
    pub esl: i32,
    pub max_template_acl: i32,
    pub public_key: [u8; PUBLIC_KEY_LEN_FFI],
    pub device_udid: [u8; UDID_LEN_FFI],
    pub signed_remote_executor_info: MessageArrayFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct AddExecutorInputFfi {
    pub info: ExecutorRegisterInfoFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct AddExecutorOutputFfi {
    pub index: u64,
    pub public_key: [u8; PUBLIC_KEY_LEN_FFI],
    pub template_ids: TemplateIdArrayFfi,
}

// DeleteExecutor
#[repr(C)]
#[derive(Copy, Clone)]
pub struct DeleteExecutorInputFfi {
    pub index: u64,
}

pub type DeleteExecutorOutputFfi = PlaceHolderFfi;

// OpenSession
#[repr(C)]
#[derive(Copy, Clone)]
pub struct OpenSessionInputFfi {
    pub user_id: i32,
}

#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct OpenSessionOutputFfi {
    pub challenge: [u8; CHALLENGE_LEN_FFI],
}

// CloseSession
#[repr(C)]
#[derive(Copy, Clone)]
pub struct CloseSessionInputFfi {
    pub user_id: i32,
}

pub type CloseSessionOutputFfi = PlaceHolderFfi;

// UpdateEnrollmentResult
#[repr(C)]
#[derive(Copy, Clone)]
pub struct UpdateEnrollmentResultInputFfi {
    pub user_id: i32,
    pub schedule_result: MessageArrayFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct EnrollResultInfoFfi {
    pub credential_id: u64,
    pub old_info: CredentialInfoFfi,
    pub root_secret: MessageArrayFfi,
    pub old_root_secret: MessageArrayFfi,
    pub auth_token: AuthTokenArrayFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct UpdateEnrollmentResultOutputFfi {
    pub info: EnrollResultInfoFfi,
}

// CancelEnrollment
#[repr(C)]
#[derive(Copy, Clone)]
pub struct CancelEnrollmentInputFfi {
    pub user_id: i32,
}

pub type CancelEnrollmentOutputFfi = PlaceHolderFfi;

// DeleteCredential
#[repr(C)]
#[derive(Copy, Clone)]
pub struct DeleteCredentialInputFfi {
    pub user_id: i32,
    pub credential_id: u64,
    pub auth_token: AuthTokenArrayFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct DeleteCredentialOutputFfi {
    pub operate_type: i32,
    pub schedule_info: ScheduleInfoFfi,
    pub credential_infos: CredentialArrayFfi,
}

// GetCredential
#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetCredentialInputFfi {
    pub user_id: i32,
    pub auth_type: i32,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetCredentialOutputFfi {
    pub infos: CredentialArrayFfi,
}

// GetUserInfo
#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetUserInfoInputFfi {
    pub user_id: i32,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetUserInfoOutputFfi {
    pub secure_uid: u64,
    pub pin_sub_type: i32,
    pub infos: EnrolledInfoArrayFfi,
}

// DeleteUser
#[repr(C)]
#[derive(Copy, Clone)]
pub struct DeleteUserInputFfi {
    pub user_id: i32,
    pub auth_token: AuthTokenArrayFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct DeleteUserOutputFfi {
    pub deleted_infos: CredentialArrayFfi,
    pub root_secret: MessageArrayFfi,
}

impl Default for DeleteUserOutputFfi {
    fn default() -> Self {
        DeleteUserOutputFfi {
            deleted_infos: CredentialArrayFfi::default(),
            root_secret: MessageArrayFfi::default(),
        }
    }
}

// EnforceDeleteUser
#[repr(C)]
#[derive(Copy, Clone)]
pub struct EnforceDeleteUserInputFfi {
    pub user_id: i32,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct EnforceDeleteUserOutputFfi {
    pub deleted_infos: CredentialArrayFfi,
}

// UpdateAuthenticationResult
#[repr(C)]
#[derive(Copy, Clone)]
pub struct UpdateAuthenticationResultInputFfi {
    pub context_id: u64,
    pub schedule_result: MessageArrayFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct UpdateAuthenticationResultOutputFfi {
    pub info: AuthResultInfoFfi,
    pub enrolled_state: EnrolledStateFfi,
}

// CancelAuthentication
#[repr(C)]
#[derive(Copy, Clone)]
pub struct CancelAuthenticationInputFfi {
    pub context_id: u64,
}

pub type CancelAuthenticationOutputFfi = PlaceHolderFfi;

// GetAvailableStatus
#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetAvailableStatusInputFfi {
    pub user_id: i32,
    pub auth_type: i32,
    pub auth_trust_level: i32,
}

pub type GetAvailableStatusOutputFfi = PlaceHolderFfi;

// GetValidSolution
#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetValidSolutionInputFfi {
    pub user_id: i32,
    pub auth_types: Int32ArrayFfi,
    pub auth_trust_level: i32,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetValidSolutionOutputFfi {
    pub valid_types: Int32ArrayFfi,
}

// BeginAuthentication
#[repr(C)]
#[derive(Copy, Clone)]
pub struct AuthParamBaseFfi {
    pub user_id: i32,
    pub auth_trust_level: i32,
    pub executor_sensor_hint: u32,
    pub challenge: [u8; CHALLENGE_LEN_FFI],
}

impl Default for AuthParamBaseFfi {
    fn default() -> Self {
        AuthParamBaseFfi {
            user_id: 0,
            auth_trust_level: 0,
            executor_sensor_hint: 0,
            challenge: [0; CHALLENGE_LEN_FFI],
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct AuthParamFfi {
    pub base_param: AuthParamBaseFfi,
    pub auth_type: i32,
    pub auth_intent: i32,
    pub is_os_account_verified: u8,
    pub collector_udid: [u8; UDID_LEN_FFI],
}

impl Default for AuthParamFfi {
    fn default() -> Self {
        AuthParamFfi {
            base_param: AuthParamBaseFfi::default(),
            auth_type: 0,
            auth_intent: 0,
            is_os_account_verified: 0,
            collector_udid: [0; UDID_LEN_FFI],
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct BeginAuthenticationInputFfi {
    pub context_id: u64,
    pub param: AuthParamFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct BeginAuthenticationOutputFfi {
    pub schedule_infos: ScheduleInfoArrayFfi,
}

impl Default for BeginAuthenticationOutputFfi {
    fn default() -> Self {
        BeginAuthenticationOutputFfi {
            schedule_infos: ScheduleInfoArrayFfi::default(),
        }
    }
}

// BeginEnrollment
#[repr(C)]
#[derive(Copy, Clone)]
pub struct EnrollParamFfi {
    pub auth_type: i32,
    pub executor_sensor_hint: u32,
    pub user_id: i32,
    pub user_type: i32,
    pub auth_sub_type: i32,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct BeginEnrollmentInputFfi {
    pub auth_token: AuthTokenArrayFfi,
    pub param: EnrollParamFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct BeginEnrollmentOutputFfi {
    pub info: ScheduleInfoFfi,
}

impl Default for BeginEnrollmentOutputFfi {
    fn default() -> Self {
        BeginEnrollmentOutputFfi {
            info: ScheduleInfoFfi::default(),
        }
    }
}

// GetAllUserInfo
pub type GetAllUserInfoInputFfi = PlaceHolderFfi;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetAllUserInfoOutputFfi {
    pub user_infos: UserInfoArrayFfi,
}

// GetAllExtUserInfo
pub type GetAllExtUserInfoInputFfi = PlaceHolderFfi;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetAllExtUserInfoOutputFfi {
    pub user_infos: ExtUserInfoArrayFfi,
}

// GetEnrolledState
#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetEnrolledStateInputFfi {
    pub user_id: i32,
    pub auth_type: i32,
}

#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct GetEnrolledStateOutputFfi {
    pub enrolled_state: EnrolledStateFfi,
}

// CheckReuseUnlockResult
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ReuseUnlockParamFfi {
    pub base_param: AuthParamBaseFfi,
    pub auth_types: Int32ArrayFfi,
    pub reuse_unlock_result_duration: u64,
    pub reuse_unlock_result_mode: i32,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct ReuseUnlockInfoFfi {
    pub auth_type: i32,
    pub token: AuthTokenArrayFfi,
    pub enrolled_state: EnrolledStateFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct CheckReuseUnlockResultInputFfi {
    pub reuse_param: ReuseUnlockParamFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct CheckReuseUnlockResultOutputFfi {
    pub reuse_info: ReuseUnlockInfoFfi,
}

// PrepareRemoteAuth
#[repr(C)]
#[derive(Copy, Clone)]
pub struct PrepareRemoteAuthInputFfi {
    pub remote_udid: [u8; UDID_LEN_FFI],
}

impl Default for PrepareRemoteAuthInputFfi {
    fn default() -> Self {
        PrepareRemoteAuthInputFfi {
            remote_udid: [0; UDID_LEN_FFI],
        }
    }
}

pub type PrepareRemoteAuthOutputFfi = PlaceHolderFfi;

// GetLocalScheduleFromMessage
#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetLocalScheduleFromMessageInputFfi {
    pub remote_udid: [u8; UDID_LEN_FFI],
    pub message: MessageArrayFfi,
}

impl Default for GetLocalScheduleFromMessageInputFfi {
    fn default() -> Self {
        GetLocalScheduleFromMessageInputFfi {
            remote_udid: [0; UDID_LEN_FFI],
            message: MessageArrayFfi::default(),
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetLocalScheduleFromMessageOutputFfi {
    pub schedule_info: ScheduleInfoFfi,
}

// GetSignedExecutorInfo
#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetSignedExecutorInfoInputFfi {
    pub auth_types: Int32ArrayFfi,
    pub executor_role: i32,
    pub remote_udid: [u8; UDID_LEN_FFI],
}

impl Default for GetSignedExecutorInfoInputFfi {
    fn default() -> Self {
        GetSignedExecutorInfoInputFfi {
            auth_types: Int32ArrayFfi::default(),
            executor_role: 0,
            remote_udid: [0; UDID_LEN_FFI],
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetSignedExecutorInfoOutputFfi {
    pub signed_executor_info: MessageArrayFfi,
}

// GetAuthResultFromMessage
#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetAuthResultFromMessageInputFfi {
    pub remote_udid: [u8; UDID_LEN_FFI],
    pub message: MessageArrayFfi,
}

impl Default for GetAuthResultFromMessageInputFfi {
    fn default() -> Self {
        GetAuthResultFromMessageInputFfi {
            remote_udid: [0; UDID_LEN_FFI],
            message: MessageArrayFfi::default(),
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetAuthResultFromMessageOutputFfi {
    pub auth_result_info: AuthResultInfoFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct GlobalConfigParamFfi {
    pub type_: i32,
    pub pin_expired_period: i64,
    pub enable_status: u8,
    pub user_ids: Int32ArrayFfi,
    pub auth_types: Int32ArrayFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct SetGlobalConfigParamInputFfi {
    pub param: GlobalConfigParamFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct ExecutorExpiredInfoFfi {
    pub schedule_id: u64,
    pub schedule_mode: u32,
    pub auth_expired_sys_time: u64,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct SetGlobalConfigParamOutputFfi {
    pub param: ExecutorExpiredInfoFfi,
}

// GetCredentialById
#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetCredentialByIdInputFfi {
    pub credential_id: u64,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct GetCredentialByIdOutputFfi {
    pub info: CredentialInfoFfi,
}

// VerifyAuthToken
#[repr(C)]
#[derive(Copy, Clone)]
pub struct VerifyAuthTokenInputFfi {
    pub token_in: AuthTokenArrayFfi,
    pub allowable_duration: u64,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct VerifyAuthTokenOutputFfi {
    pub version: u32,
    pub user_id: i32,
    pub challenge: [u8; CHALLENGE_LEN_FFI],
    pub time_interval: u64,
    pub auth_trust_level: i32,
    pub auth_type: i32,
    pub auth_mode: i32,
    pub security_level: u32,
    pub token_type: i32,
    pub secure_uid: u64,
    pub enrolled_id: u64,
    pub credential_id: u64,
    pub collector_udid: [u8; UDID_LEN_FFI],
    pub verifier_udid: [u8; UDID_LEN_FFI],
    pub root_secret: [u8; ROOT_SECRET_LEN_FFI],
}

impl Default for VerifyAuthTokenOutputFfi {
    fn default() -> Self {
        VerifyAuthTokenOutputFfi {
            version: 0,
            user_id: 0,
            challenge: [0; CHALLENGE_LEN_FFI],
            time_interval: 0,
            auth_trust_level: 0,
            auth_type: 0,
            auth_mode: 0,
            security_level: 0,
            token_type: 0,
            secure_uid: 0,
            enrolled_id: 0,
            credential_id: 0,
            collector_udid: [0; UDID_LEN_FFI],
            verifier_udid: [0; UDID_LEN_FFI],
            root_secret: [0; ROOT_SECRET_LEN_FFI],
        }
    }
}

// UpdateAbandonResult
#[repr(C)]
#[derive(Copy, Clone)]
pub struct UpdateAbandonResultInputFfi {
    pub user_id: i32,
    pub schedule_result: MessageArrayFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct UpdateAbandonResultOutputFfi {
    pub infos: CredentialArrayFfi,
}

// ClearUnavailableCredential
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ClearUnavailableCredentialInputFfi {
    pub user_ids: UserIdArrayFfi,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct ClearUnavailableCredentialOutputFfi {
    pub credentials: CredentialArrayFfi,
}

#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum CommandId {
    Init = 1,
    AddExecutor = 2,
    DeleteExecutor = 3,
    OpenSession = 4,
    CloseSession = 5,
    UpdateEnrollmentResult = 6,
    CancelEnrollment = 7,
    DeleteCredential = 8,
    GetCredential = 9,
    GetUserInfo = 10,
    DeleteUser = 11,
    EnforceDeleteUser = 12,
    UpdateAuthenticationResult = 13,
    CancelAuthentication = 14,
    GetAvailableStatus = 15,
    GetValidSolution = 16,
    BeginAuthentication = 17,
    BeginEnrollment = 18,
    GetAllUserInfo = 19,
    GetAllExtUserInfo = 20,
    GetEnrolledState = 21,
    CheckReuseUnlockResult = 22,
    PrepareRemoteAuth = 24,
    GetLocalScheduleFromMessage = 25,
    GetSignedExecutorInfo = 26,
    GetAuthResultFromMessage = 27,
    SetGlobalConfigParam = 28,
    GetCredentialById = 29,
    VerifyAuthToken = 30,
    UpdateAbandonResult = 31,
    ClearUnavailableCredential = 32,
}

impl TryFrom<i32> for CommandId {
    type Error = ErrorCode;
    fn try_from(value: i32) -> Result<Self, ErrorCode> {
        match value {
            1 => Ok(CommandId::Init),
            2 => Ok(CommandId::AddExecutor),
            3 => Ok(CommandId::DeleteExecutor),
            4 => Ok(CommandId::OpenSession),
            5 => Ok(CommandId::CloseSession),
            6 => Ok(CommandId::UpdateEnrollmentResult),
            7 => Ok(CommandId::CancelEnrollment),
            8 => Ok(CommandId::DeleteCredential),
            9 => Ok(CommandId::GetCredential),
            10 => Ok(CommandId::GetUserInfo),
            11 => Ok(CommandId::DeleteUser),
            12 => Ok(CommandId::EnforceDeleteUser),
            13 => Ok(CommandId::UpdateAuthenticationResult),
            14 => Ok(CommandId::CancelAuthentication),
            15 => Ok(CommandId::GetAvailableStatus),
            16 => Ok(CommandId::GetValidSolution),
            17 => Ok(CommandId::BeginAuthentication),
            18 => Ok(CommandId::BeginEnrollment),
            19 => Ok(CommandId::GetAllUserInfo),
            20 => Ok(CommandId::GetAllExtUserInfo),
            21 => Ok(CommandId::GetEnrolledState),
            22 => Ok(CommandId::CheckReuseUnlockResult),
            24 => Ok(CommandId::PrepareRemoteAuth),
            25 => Ok(CommandId::GetLocalScheduleFromMessage),
            26 => Ok(CommandId::GetSignedExecutorInfo),
            27 => Ok(CommandId::GetAuthResultFromMessage),
            28 => Ok(CommandId::SetGlobalConfigParam),
            29 => Ok(CommandId::GetCredentialById),
            30 => Ok(CommandId::VerifyAuthToken),
            31 => Ok(CommandId::UpdateAbandonResult),
            32 => Ok(CommandId::ClearUnavailableCredential),
            _ => {
                log_e!("Invalid command id: {}", value);
                Err(ErrorCode::BadParam)
            }
        }
    }
}

// cxxbridge module
// #[cxx::bridge]
// mod ffi {
//     pub struct RustCommandParam {
//         pub command_id: i32,
//         pub input_data: *const u8,
//         pub input_data_len: u32,
//         pub output_data: *mut u8,
//         pub output_data_len: u32,
//         pub common_output_data: *mut u8,
//         pub common_output_data_len: u32,
//     }

//     extern "Rust" {
//         fn init_rust_env() -> i32;
//         fn uninit_rust_env() -> i32;
//         fn invoke_rust_command(param: RustCommandParam) -> i32;
//     }
// }

// pub use ffi::RustCommandParam;

#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum CallerTypeFfi {
    Ca = 0,
    Ta = 1,
}

// cbindgen module
#[repr(C)]
pub struct RustCommandParam {
    pub command_id: i32,
    pub caller_type: i32,
    pub caller_udid: [u8; UDID_LEN_FFI],
    pub input_data: *const u8,
    pub input_data_len: u32,
    pub output_data: *mut u8,
    pub output_data_len: u32,
    pub common_output_data: *mut u8,
    pub common_output_data_len: u32,
}

#[no_mangle]
pub extern "C" fn init_rust_env() -> i32 {
    match handle_rust_env_init() {
        Ok(_) => 0,
        Err(e) => e as i32,
    }
}

#[no_mangle]
pub extern "C" fn uninit_rust_env() -> i32 {
    match handle_rust_env_uninit() {
        Ok(_) => 0,
        Err(e) => e as i32,
    }
}

fn invoke_rust_command_inner(param: RustCommandParam) -> Result<(), ErrorCode> {
    ensure_or_return_val!(param.input_data_len != 0, ErrorCode::BadParam);
    ensure_or_return_val!(!param.input_data.is_null(), ErrorCode::BadParam);
    ensure_or_return_val!(param.output_data_len != 0, ErrorCode::BadParam);
    ensure_or_return_val!(!param.output_data.is_null(), ErrorCode::BadParam);
    ensure_or_return_val!(param.common_output_data_len as usize == mem::size_of::<CommonOutputFfi>(), ErrorCode::BadParam);
    ensure_or_return_val!(!param.common_output_data.is_null(), ErrorCode::BadParam);

    let caller = match (param.caller_type, param.caller_udid) {
        (0, _) => {
            Caller::Ca
        }
        (1, udid) => {
            Caller::Ta(udid)
        }
        _ => {
            return Err(ErrorCode::BadParam);
        }
    };

    let input = unsafe { slice::from_raw_parts(param.input_data, param.input_data_len as usize) };
    let output =
        unsafe { slice::from_raw_parts_mut(param.output_data, param.output_data_len as usize) };
    let common_output = unsafe {
        slice::from_raw_parts_mut(
            param.common_output_data,
            param.common_output_data_len as usize,
        )
    };

    handle_rust_command(param.command_id, caller, input, output, common_output)
}

#[no_mangle]
pub extern "C" fn invoke_rust_command(param: RustCommandParam) -> i32 {
    match invoke_rust_command_inner(param) {
        Ok(_) => 0,
        Err(e) => e as i32,
    }
}